<template>
  <div ref="terminal" id="Terminal" class="xterm" style="height: 10%;width: 100%;"></div>
  <!-- <button @click="tt">close</button> -->
</template>
<script lang="ts" setup>
import WebSocketBean from '@/util/websocket/WebSocketBean'
import { IWebSocketBeanParam } from '@/util/websocket/websocket'
import { nextTick, onMounted, ref, reactive, onUnmounted, onBeforeMount } from 'vue'
import 'xterm/css/xterm.css'
import 'xterm/lib/xterm.js'
import { IBufferRange, IDecoration, IDecorationOptions, IDisposable, ILinkProvider, IMarker, ITerminalAddon, Terminal } from 'xterm'
import { Message } from '@/entity/entitys'
// xterm.js的插件，使终端的尺寸适合包含元素。
import { FitAddon } from 'xterm-addon-fit'
// xterm.js的附加组件，用于附加到Web Socket
import { AttachAddon } from 'xterm-addon-attach'
let wsTime: any = reactive<any>("");
//import System from '~/utils/System'
let term: Terminal = reactive<Terminal>(new Terminal({
  rows: 40, //行数，影响最小高度
  cols: 100, // 列数，影响最小宽度
  convertEol: true, //启用时，光标将设置为下一行的开头
  scrollback: 50, //终端中的滚动条回滚量
  disableStdin: false, //是否应禁用输入。
  cursorStyle: "underline", //光标样式
  cursorBlink: true, //光标闪烁
  theme: {
    foreground: "#F8F8F8",
    background: "#2D2E2C",
    cursor: "help", //设置光标

  },
  fontFamily: '"Cascadia Code", Menlo, monospace',
}));
let fitAddon: FitAddon = new FitAddon();
const terminal = ref();

// 用户输入
let command: String = reactive<String>("");
onMounted(() => {
  if ("WebSocket" in window) {
    nextTick(() => {
      userWrite();
    });
    start();
  } else {
    console.log("浏览器不支持 WebSocket..");
  }

})

onUnmounted(() => {
  close();
})
enum MessageType {
  /**
   * 收到发来的消息
   */
  Get,
  /**
   * 发送到服务器的消息
   */
  Send,
  /**
   * 通知
   */
  Message
}

const conf = reactive({
  status: '未连接',
  messagetype: {
    [MessageType.Get]: '收到',
    [MessageType.Send]: '发送',
    [MessageType.Message]: '通知'
  } as any,
  message: [] as {
    time: any
    type: MessageType
    data: any
  }[],
  url: 'ws://127.0.0.1:5555',
  send: ''
})

const addMessage = (type: MessageType, ctx: any) => {
  conf.message.push({
    time: new Date().toJSON(),
    type: type,
    data: ctx
  })
}

const sendSuffix = ''

/**
* 获取连接参数，也可以直接写入，这里是因为对地址进行了配置，所以每次连接都更新一次地址
*/
const getParam = () => {
  return {
    url: conf.url,
    needReconnect: true,
    reconnectGapTime: 3000,
    sendSuffix,
    messageSuffix: sendSuffix,
    heartSend: 'JAVA',
    heartGet: 'JAVA',
    heartGapTime: 10000,
    onopen: () => {
      addMessage(MessageType.Message, '连接成功')
    },
    onmessage: (data: any) => {
      //console.log("data.data: " + data.data.message_type)
      let message: Message =JSON.parse(data.data) as Message;
      if (message.message_type != "HEARTBEAT") {
        //sp.forEach((ctx: any) => {
          term.write('\r\n')
          writeOfColor(message.data, "0;", "37m");
          term.write('\r\n$ ')
          addMessage(MessageType.Get, message.data)
        //})
      }else{
        console.log("HEARTBEAT 心跳测试: " + message.data)
      }


    },
    onerror: () => {
      addMessage(MessageType.Message, '连接失败:' + conf.url)
    }
  } as IWebSocketBeanParam
}
interface Info {
  Message_type: string;
  data:string;
}
/**
* websocket示例，主要维护和使用对象
*/
const ws = new WebSocketBean(getParam())
const start = () => {
  // ws.start()
  ws.start(getParam())
  console.log("已建立连接：", event);
  // 输入换行符可让终端显示当前用户的工作路径
  // ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
  // 窗口自适应插件
  // 窗口尺寸变化时，终端尺寸自适应

  fitAddon.activate(term)
  //给新的这个ws服务使用依赖设置样式
  term.loadAddon(fitAddon);
  //给新的这个ws服务使用依赖初始化
  //term.loadAddon(attachAddon)
  term.open(terminal.value);
  // // 聚焦闪烁光标
  term.focus();
  ////先默认一次适应大小
  setTimeout(() => {
    fitAddon.fit();
  }, 1000)
  window.onresize = () => {
    fitAddon.fit();
  };
  writeDefaultInfo();
}

// 自定义终端默认展示内容
function writeDefaultInfo() {
  let defaultInfo = [
    "┌\x1b[1m terminals \x1b[0m─────────────────────────────────────────────────────────────────┐ ",
    "│                                                                            │ ",
    "│  \x1b[1;34m 欢迎使用Web Docker SSH \x1b[0m                                                  │ ",
    "│                                                                            │ ",
    "└────────────────────────────────────────────────────────────────────────────┘ ",
  ];
  // 测试颜色区间
  // let arr = Array.from({length:100},(v,i)=>v = i)
  // console.log(arr)
  // arr.map((item,i) => {
  //     defaultInfo.push(`Hello from \x1B[1;3;${i}m ${i} \x1B[0m  \u2764\ufe0f   ${i}`)
  // })
  term.write(defaultInfo.join("\n\r"));
  //writeOfColor("\n\r我是加粗斜体红色的字呀", "1;3;", "31m");
  term.write('\n\r$ ')
};
//
function writeOfColor(txt: string | ArrayBuffer | null, fontCss = "", bgColor = "") {
  // 在Linux脚本中以 \x1B[ 开始，中间前部分是样式+内容，以 \x1B[0m 结尾
  // 示例 \x1B[1;3;31m 内容 \x1B[0m
  // fontCss
  // 0;-4;字体样式（0;正常 1;加粗 2;变细 3;斜体 4;下划线）
  // bgColor
  // 30m-37m字体颜色（30m:黑色 31m:红色 32m:绿色 33m:棕色字 34m:蓝色 35m:洋红色/紫色 36m:蓝绿色/浅蓝色 37m:白色）
  // 40m-47m背景颜色（40m:黑色 41m:红色 42m:绿色 43m:棕色字 44m:蓝色 45m:洋红色/紫色 46m:蓝绿色/浅蓝色 47m:白色）
  term.write(`\x1B[${fontCss}${bgColor}${txt}\x1B[0m`);
};

// 监听输入
function userWrite() {
  term.onData((e) => {
    switch (e) {
      case "\u0003": // Ctrl+C
        term.write("^C ");
        term.write("\r\n$ ");
        break;
      case "\r": // Enter
        if (command == "clear") {
          term.clear()
          fitAddon.fit();
          command = "";
          term.write('\r\n$ ')
        } else if(command!=""&&command!=undefined){
          ws.send(JSON.stringify({ message_type: "COMMAND",data: command}));//根据后台返回的数据,需要传入一个对象,里边key值为message,并对这个对象进行序列化
          // this.ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
          command = "";
        }

        break;
      case "\u007F": // Backspace (DEL)
        // Do not delete the prompt
        console.log("{}:", term)
        term.write("\b \b");
        if (command.length > 0) {
          command = command.substr(
            0,
            command.length - 1
          );
        }
        break;
      default: // Print all other characters for demo
        if (
          (e >= String.fromCharCode(0x20) &&
            e <= String.fromCharCode(0x7e)) ||
          e >= "\u00a0"
        ) {
          command += e;
          writeOfColor(e, "2;3;", "33m");
          console.log("用户输入command", command);
        }
    }
  });
}
const close = () => {
  ws.dispose()
  addMessage(MessageType.Message, '关闭连接成功')
}

const sendMessage = () => {
  if (ws.status === 1) {
    const sendStatus = ws.send(conf.send)
    if (sendStatus) {
      addMessage(MessageType.Send, conf.send)
      console.log("发送成功")
    }
  } else {
    console.log("未连接")
  }
}
</script>
